package com.yunli.mall.common.schema;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.google.common.base.Joiner;
import com.yunli.mall.common.exception.MallRuntimeException;
import com.yunli.mall.common.exception.ErrorCode;
import com.yunli.mall.common.exception.ErrorDescription;
import lombok.Data;

import java.io.Serializable;
import java.util.Optional;

/**
 * @author wangyue
 * @date 2019-11-13 16:41
 */
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public class ResponseInvoke<T> implements Serializable {

    private Integer code;
    private String message;
    private T result;
    private final static Integer OK = 0;
    private final static String OK_MSG = "SUCCESS";

    /**
     * 构造-成功
     */
    private ResponseInvoke() {
        this.code = OK;
        this.message = OK_MSG;
    }

    /**
     * 构造-有结果
     *
     * @param t t
     */
    private ResponseInvoke(T t) {
        this.code = OK;
        this.message = OK_MSG;
        this.result = t;
    }

    /**
     * 构造
     *
     * @param code code
     */
    private ResponseInvoke(Integer code) {
        this.code = code;
    }

    /**
     * 构造
     *
     * @param code    code
     * @param message message
     */
    private ResponseInvoke(Integer code, String message) {
        this.code = code;
        this.message = message;
    }

    /**
     * 构造
     *
     * @param code    code
     * @param message message
     * @param result  result
     */
    private ResponseInvoke(Integer code, String message, T result) {
        this.code = code;
        this.message = message;
        this.result = result;
    }

    /**
     * 构造
     *
     * @param errorDescription errorDescription
     */
    private ResponseInvoke(ErrorDescription errorDescription) {
        this.code = errorDescription.getCode();
        this.message = errorDescription.getMessage();
    }

    /**
     * 构造 使用message作为错误消息
     *
     * @param errorDescription errorDescription
     * @param message          message
     */
    private ResponseInvoke(ErrorDescription errorDescription, String message) {
        this.code = errorDescription.getCode();
        this.message = message;
    }

    /**
     * 构造-异常
     *
     * @param e e
     */
    private ResponseInvoke(Exception e) {
        if (e instanceof ErrorDescription) {
            this.code = ((ErrorDescription) e).getCode();
            this.message = ((ErrorDescription) e).getMessage();
        } else {
            this.code = ErrorCode.INTERNAL_ERROR.getCode();
            this.message = e.getMessage();
        }
    }

    /**
     * 构造
     *
     * @param e       e
     * @param message message
     */
    private ResponseInvoke(Exception e, String message) {
        this(e);
        this.message = message;
    }

    // -----

    /**
     * 成功-无数据
     *
     * @return 成功
     */
    public static <T> ResponseInvoke<T> ok() {
        return new ResponseInvoke<>();
    }

    /**
     * 成功-有数据
     *
     * @param t   t
     * @param <T> <T>
     * @return 成功结果
     */
    public static <T> ResponseInvoke<T> ok(T t) {
        return new ResponseInvoke<>(t);
    }

    /**
     * 错误
     *
     * @param e e
     * @return 错误
     */
    public static <T> ResponseInvoke<T> error(Exception e) {
        return new ResponseInvoke<>(e);
    }

    /**
     * 错误-取message
     *
     * @param e       e
     * @param message message
     * @return 错误
     */
    public static <T> ResponseInvoke<T> error(Exception e, String message) {
        return new ResponseInvoke<>(e, message);
    }

    /**
     * 错误
     *
     * @param code    code
     * @param message message
     * @return 错误
     */
    public static <T> ResponseInvoke<T> error(Integer code, String message) {
        return new ResponseInvoke<>(code, message);
    }

    /**
     * 错误
     *
     * @param errorDescription errorDescription
     * @param messages         messages
     * @return 错误
     */
    public static <T> ResponseInvoke<T> error(ErrorDescription errorDescription, String... messages) {
        // 用","拼接message
        String message = messages.length == 0 ? errorDescription.getMessage() : Joiner.on(",").join(messages);
        return new ResponseInvoke<>(errorDescription, message);
    }

    /**
     * @param responseInvoke responseInvoke
     * @param <T>            <T>
     * @return t
     */
    public static <T> T isOk(ResponseInvoke<T> responseInvoke) {
        return responseInvoke.isOk();
    }

    /**
     * @return T
     * @throws MallRuntimeException MallRuntimeException
     */
    public T isOk() {
        // 成功的返回data
        if (OK.equals(this.getCode())) {
            return this.getResult();
        } else {
            // 否则抛出RuntimeException异常
            throw new MallRuntimeException(this.getMessage());
        }
    }

    /**
     * @return Optional<T>
     */
    public Optional<T> isOptionalOk() {
        // 成功的返回Optional包装的data
        if (OK.equals(this.getCode())) {
            return Optional.ofNullable(this.getResult());
        } else {
            // 否则抛出RuntimeException
            throw new MallRuntimeException(this.getMessage());
        }
    }

}
